import React, { Children, Component, createRef } from "react";
import { SwiperItem } from './swiper.item';
import './style.scss';

type DirectionType = 'horizontal' | 'vertical';

export interface SwiperProps {
  children: any;
  direction?: DirectionType;
  active?: number | string;
  auto?: string | number | boolean;
  duration?: number;
  sensitivity?: number;
  resistance?: number;
  loop?: boolean;
  onChange?: (key: number) => void;
}
export interface SwiperState {
  activeIndex: number;
}

export class Swiper extends Component<SwiperProps> {
  private _active: number | string = 0;
  private warpRef: any = null;
  private swiperItems: any[] = [];
  private distance: number = 0;
  private setter: any = null;
  private timer: any = null;

  constructor(props: SwiperProps){
    super(props);
    this.active = parseInt(this.props.active + '', 10) || 0;
    this.warpRef = createRef();
  }

  private setDom(): void {
    const { direction = 'horizontal' } = this.props;
    this.swiperItems = this.warpRef?.current?.querySelectorAll('.mkreact-swiper-item');
    if(this.swiperItems?.length > 0){
      const item: HTMLElement = this.swiperItems[0];
      this.distance = direction === 'horizontal' ? +item.offsetWidth : +item.offsetHeight;
    }
  }

  private init(): void {
    if(typeof window !== 'undefined'){ this.autoplay() };
    //相当于手动版本
    this.setTransition('0');
    this.setTransform();
    this.warpRef.current.style.visibility = 'visible';
  }

  private setTransition(duration?: string | number): void{
    duration = duration || this.props.duration || 600;
    const transition: string = typeof duration === 'number' ? (duration + 'ms') : duration;

    this.swiperItems.forEach((item: HTMLElement) => {
      const element: HTMLElement = item;
      element.style.webkitTransition = transition;
      element.style.transition = transition;
    });
  }

  private setTransform(offset: number = 0): void{
    const { direction = 'horizontal' } = this.props;

    this.swiperItems.forEach((item: HTMLElement, i: number) => {
      const element: HTMLElement = item;
      //相当于你要去第几张图片，图片就走几张的长度，加上offset再偏移一张的距离，就是要显示的图片
      const distance: number = (i - (+this.active)) * this.distance + offset;
      const transform: string = direction === 'horizontal' ? `translate3d(${distance}px, 0, 0)` : `translate3d(0, ${distance}px, 0)`;
      element.style.webkitTransform = transform;
      element.style.transform = transform;
    })
  }

  private autoplay(): void {
    const { auto, children } = this.props;
    /**
     * 这部分代码，很关键的一步
     */
    const item = Children.toArray(children).filter((child: any) => {
      return child?.type === SwiperItem;
    });
    if(auto && item.length > 1){
      this.clearTimer();
      this.setter = setTimeout(() => {
        this.next();
      }, parseInt(auto + '', 10));
    }
  }

  private clearTimer(): void {
    clearTimeout(this.setter);
    this.setter = null;
  }

  public next(num: number = 1): void {
    //关键在于是不是最后一张图，和要不要循环播放
    const { loop, auto, children } = this.props;
    let active = +this.active + num;
    if(loop || (auto && this.setter)){
      active = active > (children.length - 1) ? 0 : active;
    }else {
      //如果设置不要循环播放，就直接到最后一张图片就不动了
      active = active > (children.length - 1) ? (children.length - 1) : active;
    }
    this.active = active;
  }

  public prev(num: number = 1): void {
    const { loop, auto, children } = this.props;
    let active = +this.active - num;
    if(loop || (auto && this.setter)){
      active = active < 0 ? (children.length - 1) : active;
    }else {
      active = active < 0 ? 0 : active;
    }
    this.active = active;
  }

  //拿一个参数的赋值，当作函数来用了
  set active(val: number | string){
    if(val !== this._active){
      const { onChange=()=>{}, duration = 600 } = this.props;
      this._active = val;
      this.autoplay();
      this.setTransition(duration);
      this.setTransform();
      onChange(+val);
    }
  }

  get active(){
    return this._active;
  }

  componentDidMount(){
    this.setDom();
    this.init();
  }

  componentDidUpdate(prevProps: SwiperProps){
    const { active, children } = this.props;
    if(this.active !== active){
      this.active = active ? +active : 0;
    }
    if(children !== prevProps.children){
      this.timer = setTimeout(() => {
        this.setDom(); 
      });
    }
  }

  componentWillUnmount(){
    clearTimeout(this.timer);
    clearTimeout(this.setter);
    this.warpRef.current = null;
  }

  render(){
    const { children } = this.props;
    return (
      <div className="mkreact-swiper">
        <div className="mkreact-swiper-wrap" ref={ this.warpRef }>{ children }</div>
      </div>
    )
  }
}